﻿namespace Morus
{
    using System;
    using System.Diagnostics;
    using System.Text.RegularExpressions;
    using System.Globalization;

    public static partial class StringExtension
    {
        private static readonly Regex WebUrlExpression = new Regex(@"(http|https)://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?", RegexOptions.Singleline | RegexOptions.Compiled);
        private static readonly Regex EmailExpression = new Regex(@"^([0-9a-zA-Z]+[-._+&])*[0-9a-zA-Z]+@([-0-9a-zA-Z]+[.])+[a-zA-Z]{2,6}$", RegexOptions.Singleline | RegexOptions.Compiled);

        [DebuggerStepThrough]
        public static bool IsWebUrl(this string target)
        {
            return target.IsNotEmpty() && WebUrlExpression.IsMatch(target);
        }

        [DebuggerStepThrough]
        public static bool IsEmail(this string target)
        {
            return target.IsNotEmpty() && EmailExpression.IsMatch(target);
        }

        [DebuggerStepThrough]
        public static bool IsEmpty(this string target)
        {
            return (target == null) || (target.Length == 0);
        }

        [DebuggerStepThrough]
        public static bool IsNotEmpty(this string target)
        {
            return target.IsEmpty() == false;
        }

        [DebuggerStepThrough]
        public static string FormatWith(this string target, params object[] args)
        {
            Check.Argument.IsNotEmpty(target, "target");
            Check.Argument.IsNotNull(args, "args");

            return string.Format(CultureInfo.CurrentCulture, target, args);
        }

        [DebuggerStepThrough]
        public static string NullSafe(this string target)
        {
            return target ?? string.Empty;
        }

        [DebuggerStepThrough]
        public static string IfEmpty(this string target, Func<string> defaultValue)
        {
            return target.IsEmpty() ? defaultValue() : target;
        }

        [DebuggerStepThrough]
        public static string Shorten(this string target, int length, string suffix)
        {
            Check.Argument.IsNotEmpty(target, "target");
            Check.Argument.IsNotNegative(length, "length");

            if (target.Length <= length)
                return target;
            else
                return target.Substring(0, length - suffix.Length) + suffix;
        }

        [DebuggerStepThrough]
        public static TEnum ToEnum<TEnum>(this string target)
            where TEnum : struct
        {
            Check.Argument.IsNotEmpty(target, "target");

            return (TEnum)Enum.Parse(typeof(TEnum), target, true);
        }

        [DebuggerStepThrough]
        public static TEnum ToEnum<TEnum>(this string target, TEnum defaultValue)
            where TEnum : struct
        {
            if (target.IsEmpty())
                return defaultValue;
            try
            {
                return target.ToEnum<TEnum>();
            }
            catch (ArgumentException)
            {
                return defaultValue;
            }
        }

        [DebuggerStepThrough]
        public static Guid ToGuid(this string target)
        {
            Check.Argument.IsNotEmpty(target, "target");

            if (target.Trim().Length == 22)
            {
                string encoded = string.Concat(target.Trim().Replace("-", "+").Replace("_", "/"), "==");

                byte[] base64 = Convert.FromBase64String(encoded);

                return new Guid(base64);
            }
            else
            {
                throw new ArgumentOutOfRangeException("target");
            }
        }
    }
}
